package ftp.connection;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.LinkedList;

import org.apache.commons.net.ftp.*;

import ftp.photoeditor.fileStructure.Directory;
import ftp.photoeditor.fileStructure.FileStructureItem;
import ftp.photoeditor.fileStructure.Photo;

public class RemoteConnection {
	private String hostname;
	private String username;
	private String password;
	private String cwd;
	
	private FTPClient client;
	
	private LinkedList<FileStructureItem> contents;
	private LinkedList<Photo> files;
	private LinkedList<Directory> directories;
	
	private boolean connected;
	
	public static RemoteConnection instance = null;
	
	
	// Constructors
	public RemoteConnection(String host, String user, String password, String cwd) {
		if(instance != null)
			return;
		
		instance = this;
		
		Connect(host, user, password, cwd);
	}
	
	public RemoteConnection(String host, String user, String password) {
		this(host, user, password, "/");
	}
	
	// Connect / Disconnect Methods
	public void Connect(String host, String user, String password, String cwd) {
		this.hostname = host;
		this.username = user;
		this.password = password;
		this.cwd = cwd;
		
		Connect();
	}
	
	public void Connect(String host, String user, String password) {
		Connect(host, user, password, "/");
	}
	
	public void Connect() {
		client = new FTPClient();
		// Try to connect to server (or catch exceptions)
		try {
			client.connect(hostname);
			client.login(username, password);
		} catch (IOException e) {
			// TODO Show Failed Connection Message
			e.printStackTrace();
		}
		
		getContents();
		connected = true;
	}
	
	public void Disconnect() {
		try {
			client.disconnect();
		} catch (IOException e) {
			// TODO Show Failed Disconnection Message
			e.printStackTrace();
		}
		
		contents.clear();
		files.clear();
		directories.clear();
		connected = false;
	}
	
	// Upload / Download
	public void uploadFile(String localPath) {
		FileInputStream local;
		try {
			local = new FileInputStream(localPath);
			
			if(client.storeFile(cwd, local))
				System.out.println("Stored!");
			else {
				System.out.println("Could not store file");
				System.out.println(client.getReplyString());
			}
			
			local.close();
		} catch (FileNotFoundException e1) {
			// TODO No local file
			e1.printStackTrace();
		} catch (IOException e) {
			// TODO Cannot send file
			e.printStackTrace();
		}
	}
	
	public void downloadFile(String fileName, String localPath) {
		FileOutputStream local;
		
		try {
			String path = cwd + "/" + fileName;
			local = new FileOutputStream(localPath + "/" + fileName);
			
			
			if(client.retrieveFile(path, local))
				System.out.println("Successfully fetched file");
			else {
				System.out.println("Cannot fetch file: " + path);
				System.out.println(client.getReplyString());
			}
			
			local.close();
			
		} catch (FileNotFoundException e) {
			// TODO Cannot find file location
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Cannot retrieve file
			e.printStackTrace();
		}
		
	}
	
	public void downloadFile(String fileName) {
		downloadFile(fileName, System.getProperty("user.home")+"\\Documents");
	}
	
	// Movement around file structure
	public void changeDirectory(String path) {
		// TODO Check for existence
		cwd = path;
		getContents();
	}
	
	public void upDirectory() {
		if(cwd.lastIndexOf("/") != 0) {
			String parent = cwd.substring(0, cwd.lastIndexOf("/"));
			changeDirectory(parent);
		}
		else changeDirectory("/");
	}
	
	public void enterDirectory(String directoryName) {
		changeDirectory(cwd + directoryName);
	}
	
	// Things
	public boolean directoryExists(String directoryName) {
		for(int i = 0; i < files.size(); i ++) {
			
		}
		
		return false;
	}
	
	// Getter / setter methods
	public LinkedList<FileStructureItem> getContents() {
		return getContents(cwd);
	}
	
	private LinkedList<FileStructureItem> getContents(String cwd) {
		LinkedList<FileStructureItem> contents = new LinkedList<FileStructureItem>();
		LinkedList<Photo> files = new LinkedList<Photo>();
		LinkedList<Directory> directories = new LinkedList<Directory>();
		try {
			for(FTPFile file : client.listFiles(cwd)) {
				if(file.isFile()) {	
					contents.add(new Photo(file.getName()));
					files.add(new Photo(file.getName()));
				}
				else {
					contents.add(new Directory(cwd, file.getName()));
					directories.add(new Directory(cwd, file.getName()));
				}
			}
		} catch (IOException e) {
			// TODO Can't get files error
			e.printStackTrace();
		}
		
		this.contents = contents;
		this.files = files;
		this.directories = directories;
		
		return contents;
	}
	
	public LinkedList<Directory> getDirectories() {
		return directories;
	}
	
	public LinkedList<Photo> getPhotos() {
		return files;
	}
	
	public LinkedList<String> getFileNames() {
		LinkedList<String> s = new LinkedList<String>();
		for(Photo p : files) {
			s.add(p.name);
		}
		return s;
	}
	
	public String listFiles() {
		String s = "";
		for(Photo p : files){
			s += (p.name + "\n");
		}
		
		return s;
	}
	
	public String listContents() {
		String s = "";
		for(FileStructureItem p : contents){
			s += (p.name + "\n");
		}
		
		return s;
	}
	
	public boolean isConnected() {
		return connected;
	}
	
	public String getPath() {
		return cwd;
	}
	
}
